#pragma once

#include <map>

#include "Property.h"

namespace XF
{
	class IProperty;
	class PropertyMakerBase;

	class PropertyFactory
	{
	private:
		static std::map<std::string, std::string>* MakersClassLinkList();
		static std::map<std::string, PropertyMakerBase*>* MakersList();

	public:
		PropertyFactory();
		~PropertyFactory();

		/**
			Registers a maker into the list
		*/
		static void RegisterMaker(std::string id, std::string typeId, PropertyMakerBase* maker);

		/**
			Unregisters a maker form the list
		*/
		static void UnregisterMaker(std::string id);

		/**
			Gets the correct maker and uses it to create a new EntityComponent
		*/
		static IProperty* CreateProperty(const std::string &id, const std::string &name);
		static IProperty* CreateProperty(const std::string &id, const std::string &name, const std::string &initialValue);

		template<class T>
		static Prop<T>* CreatePropertyUsingType(std::string name)
		{
			std::map<std::string, std::string> *makersClassLinkList = MakersClassLinkList();

			std::map<std::string, std::string>::iterator it1 = makersClassLinkList->find(typeid(T).name());

			assert(it != makersClassLinkList->end() && "PropertyFactory::CreatePropertyUsingType: Attempting to create property with unknown typeid: " + typeid(T).name());

			Prop<T> *newProp = static_cast<Prop<T>* >(CreateProperty(it1->second, name));

			assert(newProp && "PropertyFactory::CreatePropertyUsingType: attempting to create property with type that does not match maker type");

			return newProp;
		}

 		template<class T>
 		static Prop<T>* CreatePropertyUsingType(std::string name, T value)
		{
			Prop<T> *newProp = CreatePropertyUsingType<T>(name);

			assert(newProp && "PropertyFactory::CreatePropertyUsingType: attempting to create property with type that does not match maker type");

			newProp->Set(value);
			return newProp;
		}
	};
}
